package com.dubito.gallery.ui.gallery

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.rememberNavController
import coil.compose.AsyncImage
import com.dubito.gallery.R
import com.dubito.gallery.data.GalleryItem
import com.dubito.gallery.util.ObserveLifecycleEvent
import com.dubito.gallery.util.disableFullScreen
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

enum class GalleryScreenEvent {
    SelectSettings
}

private const val COLUMN_NUM = 4

private const val TIMEOUT_TO_CANCEL_ACTION_PER_TAP = 300L
private const val TIMEOUT_TO_CANCEL_ACTION_PER_BACK = 500L

@Composable
fun GalleryScreen(
    viewModel: GalleryViewModel = viewModel(),
    onItemSelected: (Int) -> Unit = {},
    onEvent: (GalleryScreenEvent) -> Unit = {}
) {
    val uiState by viewModel.uiState.collectAsState()
    GalleryContent(
        uiState = uiState,
        onItemSelected = onItemSelected,
        onEvent = onEvent
    )
    ObserveLifecycleEvent(onEvent = { event ->
        if (event == Lifecycle.Event.ON_RESUME) {
            viewModel.loadGallery()
        }
    })
    val context = LocalContext.current
    LaunchedEffect(key1 = true) {
        disableFullScreen(context)
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun GalleryContent(
    uiState: GalleryUiState,
    onItemSelected: (Int) -> Unit = {},
    onEvent: (GalleryScreenEvent) -> Unit = {}
) {
    val topAppBarState = rememberTopAppBarState()
    val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)

    val scrollFraction by remember {
        derivedStateOf {
            topAppBarState.overlappedFraction
        }
    }
    val statusBarColor = TopAppBarDefaults.centerAlignedTopAppBarColors()
        .containerColor(colorTransitionFraction = scrollFraction).value
    val systemUiController = rememberSystemUiController()
    SideEffect {
        systemUiController.setStatusBarColor(statusBarColor)
    }
    val snackBarHostState = remember { SnackbarHostState() }
    val scope = rememberCoroutineScope()

    Scaffold(
        snackbarHost = {
            SnackbarHost(hostState = snackBarHostState)
        },
        modifier = Modifier
            .nestedScroll(scrollBehavior.nestedScrollConnection)
            .safeDrawingPadding(),
        topBar = {
            CenterAlignedTopAppBar(
                title = { Text(text = stringResource(id = R.string.app_name)) },
                actions = {
                    if (uiState is GalleryUiState.Success) {
                        val failedMessage = stringResource(
                            id = R.string.message_when_opening_settings_failed,
                            uiState.tapCountOpenSettings
                        )
                        MultiTapIconButton(
                            tapCount = uiState.tapCountOpenSettings,
                            onTapComplete = { success ->
                                if (success) {
                                    onEvent(GalleryScreenEvent.SelectSettings)
                                } else {
                                    scope.launch {
                                        snackBarHostState.showSnackbar(failedMessage)
                                    }
                                }
                            }
                        ) {
                            Icon(
                                imageVector = Icons.Default.Settings,
                                contentDescription = stringResource(id = R.string.desc_settings)
                            )
                        }
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ) { innerPadding ->
        Box(modifier = Modifier.padding(innerPadding)) {
            if (uiState is GalleryUiState.Success) {
                Gallery(items = uiState.galleryItems, onItemSelected = onItemSelected)
            }
        }
    }
    if (uiState is GalleryUiState.Success) {
        val cancelGoBackMsg = stringResource(id = R.string.message_when_go_back_canceled, uiState.multiGoBack)
        MultiGoBackHandler(requiredCount = uiState.multiGoBack) {
            scope.launch {
                snackBarHostState.showSnackbar(cancelGoBackMsg)
            }
        }
    }
}

@Composable
fun MultiTapIconButton(
    tapCount: Int,
    onTapComplete: (Boolean) -> Unit,
    content: @Composable () -> Unit
) {
    val scope = rememberCoroutineScope()
    var job: Job? = remember { null }
    var count = remember { 0 }
    IconButton(
        onClick = {
            if (count == 0) {
                job = scope.launch {
                    delay(TIMEOUT_TO_CANCEL_ACTION_PER_TAP * tapCount)
                    onTapComplete(false)
                    count = 0
                }
            }
            count++
            if (count >= tapCount) {
                job?.cancel()
                onTapComplete(true)
                count = 0
            }
        },
        content = content
    )
}

@Composable
fun Gallery(items: List<GalleryItem>, onItemSelected: (Int) -> Unit = {}) {
    if (items.isNotEmpty()) {
        LazyVerticalGrid(columns = GridCells.Fixed(COLUMN_NUM)) {
            itemsIndexed(items) { index, item ->
                GalleryItem(item = item, onSelected = { onItemSelected(index) })
            }
        }
    }
}

@Composable
fun GalleryItem(item: GalleryItem, onSelected: () -> Unit) {
    Box(
        modifier = Modifier
            .aspectRatio(1f)
            .padding(1.dp)
            .clickable { onSelected() }
    ) {
        val filter = if (item.isVideo) {
            ColorFilter.tint(Color(0xffdddddd), BlendMode.Multiply)
        } else {
            null
        }
        AsyncImage(
            model = item.uri,
            contentDescription = "image",
            contentScale = ContentScale.Crop,
            colorFilter = filter,
            modifier = Modifier.background(MaterialTheme.colorScheme.surfaceVariant)
        )
        if (item.isVideo) {
            Image(
                painter = painterResource(id = R.drawable.videoindicator),
                contentDescription = "videoIndicator",
                modifier = Modifier
                    .align(Alignment.Center)
                    .size(50.dp)
                    .padding(4.dp)
            )
        }
    }
}


@Composable
fun MultiGoBackHandler(requiredCount: Int, onCancel: () -> Unit) {
    if (requiredCount > 1) {
        val scope = rememberCoroutineScope()
        var job by remember<MutableState<Job?>> { mutableStateOf(null) }
        var count = remember { 0 }
        var enableHandler by remember { mutableStateOf(true) }
        val lifecycleOwner = LocalLifecycleOwner.current

        BackHandler(enableHandler) {
            count++
            if (count == 1) {
                job = scope.launch {
                    delay(TIMEOUT_TO_CANCEL_ACTION_PER_BACK * requiredCount)
                    count = 0
                    enableHandler = true
                    onCancel()
                }
            }
            if (count == (requiredCount - 1)) {
                enableHandler = false
            }
        }
        DisposableEffect(key1 = true) {
            val observer = LifecycleEventObserver { _, event ->
                if (event == Lifecycle.Event.ON_PAUSE) {
                    job?.cancel()
                    count = 0
                    enableHandler = true
                }
            }
            lifecycleOwner.lifecycle.addObserver(observer)
            onDispose {
                lifecycleOwner.lifecycle.removeObserver(observer)
            }
        }
    }
}
